package com.quxiu.common.core.utils.security;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SM4;
import com.alibaba.fastjson2.JSONObject;

import java.security.KeyPair;
import java.security.MessageDigest;

/**
 * 加密工具
 *
 * @author gaoyang
 */
public class SecretUtil {

    /**
     * 生成偏移量iv
     *
     * @return
     */
    public static String generateIv() {
        String iv = RandomUtil.randomString(16);
        return iv;
    }

    /**
     * 生成SM2密钥
     * byte[] privateKey = pair.getPrivate().getEncoded();
     * byte[] publicKey = pair.getPublic().getEncoded();
     *
     * @return
     */
    public static KeyPair generateSm2Key() {
        KeyPair pair = SecureUtil.generateKeyPair("SM2");
        return pair;
    }

    /**
     * 生成SM4密钥
     *
     * @return 16进制密钥
     */
    public static String generateSm4Key() {
        byte[] key = SecureUtil.generateKey("SM4").getEncoded();
        return HexUtil.encodeHexStr(key);
    }

    /**
     * 生成RSA密钥
     * @return
     */
    public static KeyPairVo generateRsaKeyHex() {
        KeyPair pair = generateRsaKey();
        byte[] privateKey = pair.getPrivate().getEncoded();
        byte[] publicKey = pair.getPublic().getEncoded();
        return new KeyPairVo(publicKey, privateKey);
    }

    /**
     * 生成RSA密钥
     * byte[] privateKey = pair.getPrivate().getEncoded();
     * byte[] publicKey = pair.getPublic().getEncoded();
     *
     * @return
     */
    public static KeyPair generateRsaKey() {
        KeyPair pair = SecureUtil.generateKeyPair("RSA");
        return pair;
    }

    /**
     * SM4加密，CTR模式
     *
     * @param data   需要加密的数据
     * @param hexKey 16进制密钥
     * @param iv     偏移量
     * @return 加密后的数据，16进制
     */
    public static String encryptSm4CTR(String data, String hexKey, byte[] iv) {
        byte[] key = HexUtil.decodeHex(hexKey);
        SM4 sm4 = new SM4(Mode.CTR, Padding.NoPadding, key, iv);

        String encryptHex = sm4.encryptHex(data);
        return encryptHex;
    }

    /**
     * SM4解密，CTR模式
     *
     * @param dataHex 需要解密的数据（16进制）
     * @param hexKey  16进制密钥
     * @param iv      偏移量
     * @return 解密后的数据
     */
    public static String decryptSm4CTR(String dataHex, String hexKey, byte[] iv) {
        byte[] key = HexUtil.decodeHex(hexKey);
        SM4 sm4 = new SM4(Mode.CTR, Padding.NoPadding, key, iv);
        String decryptStr = sm4.decryptStr(dataHex);
        return decryptStr;
    }


    /**
     * SM4加密，CBC模式
     *
     * @param data   需要加密的数据
     * @param hexKey 16进制密钥
     * @param iv     偏移量
     * @return 加密后的数据，16进制
     */
    public static String encryptSm4CBC(String data, String hexKey, byte[] iv) {
        byte[] key = HexUtil.decodeHex(hexKey);
        SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, key, iv);

        String encryptHex = sm4.encryptHex(data);
        return encryptHex;
    }

    /**
     * SM4解密，CBC模式
     *
     * @param dataHex 需要解密的数据（16进制）
     * @param hexKey  16进制密钥
     * @param iv      偏移量
     * @return 解密后的数据
     */
    public static String decryptSm4CBC(String dataHex, String hexKey, byte[] iv) {
        byte[] key = HexUtil.decodeHex(hexKey);
        SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, key, iv);
        String decryptStr = sm4.decryptStr(dataHex);
        return decryptStr;
    }

    /**
     * SM2加密
     *
     * @param data      需要加密的数据
     * @param publicKey 公钥
     * @return
     */
    public static String encryptSm2(String data, String publicKey) {
        SM2 sm2 = SmUtil.sm2(null, publicKey);
        // 公钥加密，私钥解密
        String encryptStr = sm2.encryptBcd(data, KeyType.PublicKey);
        return encryptStr;
    }

    /**
     * SM2解密
     *
     * @param data       需要解密的数据
     * @param privateKey 私钥
     * @return
     */
    public static String decryptSm2(String data, String privateKey) {
        SM2 sm2 = SmUtil.sm2(privateKey, null);
        // 公钥加密，私钥解密
        String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(data, KeyType.PrivateKey));
        return decryptStr;
    }

    /**
     * RSA公钥加密
     *
     * @param data      需要加密的数据
     * @param publicKey 密钥
     * @return
     */
    public static String encryptRsaForPublicKey(String data, String publicKey) {
        RSA rsa = new RSA(null, publicKey);

        //公钥加密，私钥解密
        return rsa.encryptBase64(data, KeyType.PublicKey);
    }


    /**
     * RSA私钥加密
     *
     * @param data      需要加密的数据
     * @param privateKey 私钥
     * @return
     */
    public static String encryptRsaForPrivateKey(String data, String privateKey) {
        RSA rsa = new RSA(privateKey, null);

        //私钥加密，公钥解密
        return rsa.encryptBase64(data, KeyType.PrivateKey);
    }


    /**
     * RSA公钥解密
     *
     * @param data       需要解密的数据
     * @param publicKey 公钥
     * @return
     */
    public static String decryptRsaForPublicKey(String data, String publicKey) {
        RSA rsa = new RSA(null, publicKey);

        //私钥解密
        return rsa.decryptStr(data, KeyType.PublicKey);
    }

    /**
     * RSA私钥解密
     *
     * @param data       需要解密的数据
     * @param privateKey 私钥
     * @return
     */
    public static String decryptRsaForPrivateKey(String data, String privateKey) {
        RSA rsa = new RSA(privateKey, null);

        //私钥解密
        return rsa.decryptStr(data, KeyType.PrivateKey);
    }

    public static boolean testRsaKey(String publicKey, String privateKey) {
        String data  = "test";
        try {
            String a = encryptRsaForPrivateKey(data, privateKey);
            String b = decryptRsaForPublicKey(a, publicKey);
            return data.equals(b);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 签名
     * @param data
     * @param publicKey
     * @return
     */
    public static String sign(String data, String publicKey) {
        String sha256Data = getSHA256(data);
        return encryptRsaForPublicKey(sha256Data, publicKey);
    }

    /**
     * 验证签名
     * @param data
     * @param sing
     * @param privateKey
     * @return
     */
    public static boolean verifySign(String data, String sing, String privateKey) {
        try {
            String decryptSing = decryptRsaForPrivateKey(sing, privateKey);
            String sha256Data = getSHA256(data);
            if(decryptSing.equals(sha256Data)) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static String getSHA256(String str) {
        MessageDigest messageDigest;
        String encodestr = "";
        try {
            messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(str.getBytes("UTF-8"));
            encodestr = HexUtil.encodeHexStr(messageDigest.digest());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encodestr;
    }

    public static void main(String[] args) throws Exception {
        KeyPairVo key = generateRsaKeyHex();

        /*JSONObject data = new JSONObject();
        data.put("name", "张三");
        data.put("age", 18);

        String a = encryptRsaForPublicKey(data.toJSONString(), key.getPublicKey() + 1);
        System.out.println("加密：" + a);

        String b = decryptRsaForPrivateKey(a, key.getPrivateKey());
        System.out.println("解密：" + b);*/

        System.out.println("验证：" + testRsaKey(key.getPublicKey(), key.getPrivateKey()));

    }
}
